//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_memo_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/proto-gen-go.git/user_memo_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type UserMemoApiImpl struct {
	user_memo_api.UnimplementedUserMemoApiServer
}

func (apiImpl *UserMemoApiImpl) ListTag(ctx context.Context, req *user_memo_api.ListTagRequest) (*user_memo_api.ListTagResponse, error) {
	emptyList := []string{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_memo_api.ListTagResponse{
			Code:    user_memo_api.ListTagResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			TagList: emptyList,
		}, nil
	}
	tagList, err := user_dao.UserMemoDao.DistinctTag(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}

	return &user_memo_api.ListTagResponse{
		Code:    user_memo_api.ListTagResponse_CODE_OK,
		TagList: tagList,
	}, nil
}

func (apiImpl *UserMemoApiImpl) CreateMemo(ctx context.Context, req *user_memo_api.CreateMemoRequest) (*user_memo_api.CreateMemoResponse, error) {
	if req.BasicInfo.TagList == nil {
		req.BasicInfo.TagList = []string{}
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_memo_api.CreateMemoResponse{
			Code:   user_memo_api.CreateMemoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	memoId := uuid.NewString()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserMemoDao.Insert(sessCtx, &user_dao.MemoInfoDbItem{
			MemoId: memoId,
			UserId: sessionItem.UserId,
			BasicInfo: user_dao.BasicMemoInfoDbItem{
				Content: req.BasicInfo.Content,
				TagList: req.BasicInfo.TagList,
				BgColor: req.BasicInfo.BgColor,
			},
			CreateTime: nowTime,
			UpdateTime: nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &user_memo_api.CreateMemoResponse{
			Code:   user_memo_api.CreateMemoResponse_CODE_OK,
			MemoId: memoId,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*user_memo_api.CreateMemoResponse), nil
}

func (apiImpl *UserMemoApiImpl) UpdateMemo(ctx context.Context, req *user_memo_api.UpdateMemoRequest) (*user_memo_api.UpdateMemoResponse, error) {
	if req.BasicInfo.TagList == nil {
		req.BasicInfo.TagList = []string{}
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_memo_api.UpdateMemoResponse{
			Code:   user_memo_api.UpdateMemoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	exist, err := user_dao.UserMemoDao.Exist(ctx, sessionItem.UserId, req.MemoId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &user_memo_api.UpdateMemoResponse{
			Code:   user_memo_api.UpdateMemoResponse_CODE_NO_MEMO,
			ErrMsg: "备忘录不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserMemoDao.Update(sessCtx, sessionItem.UserId, req.MemoId, &user_dao.BasicMemoInfoDbItem{
			Content: req.BasicInfo.Content,
			TagList: req.BasicInfo.TagList,
			BgColor: req.BasicInfo.BgColor,
		}, nowTime)
		if err != nil {
			return nil, err
		}
		return &user_memo_api.UpdateMemoResponse{
			Code: user_memo_api.UpdateMemoResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*user_memo_api.UpdateMemoResponse), nil
}

func (apiImpl *UserMemoApiImpl) ListMemo(ctx context.Context, req *user_memo_api.ListMemoRequest) (*user_memo_api.ListMemoResponse, error) {
	emptyList := []*user_memo_api.MemoInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_memo_api.ListMemoResponse{
			Code:     user_memo_api.ListMemoResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			MemoList: emptyList,
		}, nil
	}

	count, err := user_dao.UserMemoDao.Count(ctx, sessionItem.UserId, req.FilterByTag, req.TagList)
	if err != nil {
		return nil, err
	}
	memoItemList, err := user_dao.UserMemoDao.List(ctx, sessionItem.UserId, req.FilterByTag, req.TagList, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	memoList := []*user_memo_api.MemoInfo{}
	for _, memoItem := range memoItemList {
		memoList = append(memoList, memoItem.ToMemoInfo())
	}
	return &user_memo_api.ListMemoResponse{
		Code:       user_memo_api.ListMemoResponse_CODE_OK,
		TotalCount: count,
		MemoList:   memoList,
	}, nil
}

func (apiImpl *UserMemoApiImpl) GetMemo(ctx context.Context, req *user_memo_api.GetMemoRequest) (*user_memo_api.GetMemoResponse, error) {
	emptyInfo := &user_memo_api.MemoInfo{
		BasicInfo: &user_memo_api.BasicMemoInfo{
			TagList: []string{},
		},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_memo_api.GetMemoResponse{
			Code:   user_memo_api.GetMemoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Memo:   emptyInfo,
		}, nil
	}

	memoItem, err := user_dao.UserMemoDao.Get(ctx, sessionItem.UserId, req.MemoId)
	if err != nil {
		return &user_memo_api.GetMemoResponse{
			Code:   user_memo_api.GetMemoResponse_CODE_NO_MEMO,
			ErrMsg: "备忘录不存在",
			Memo:   emptyInfo,
		}, nil
	}

	return &user_memo_api.GetMemoResponse{
		Code: user_memo_api.GetMemoResponse_CODE_OK,
		Memo: memoItem.ToMemoInfo(),
	}, nil
}

func (apiImpl *UserMemoApiImpl) RemoveMemo(ctx context.Context, req *user_memo_api.RemoveMemoRequest) (*user_memo_api.RemoveMemoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_memo_api.RemoveMemoResponse{
			Code:   user_memo_api.RemoveMemoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	exist, err := user_dao.UserMemoDao.Exist(ctx, sessionItem.UserId, req.MemoId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &user_memo_api.RemoveMemoResponse{
			Code: user_memo_api.RemoveMemoResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserMemoDao.Remove(sessCtx, sessionItem.UserId, req.MemoId)
		if err != nil {
			return nil, err
		}
		return &user_memo_api.RemoveMemoResponse{
			Code: user_memo_api.RemoveMemoResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_memo_api.RemoveMemoResponse), nil
}
